import { useDrop } from 'react-dnd'// React DnD库的放置目标钩子
import { useComponentsStore } from '../stores/components'  // 组件状态管理仓库
import { useComponentConfigStore } from '../stores/component-config'// 组件配置管理仓库
import { message } from 'antd'// Ant Design消息提示组件
//accept: string[] ：允许接收的拖拽类型数组（与拖拽源的 type 匹配），就是刚刚设置的type: props.name
//id: number ：当前容器组件的 ID，用于给新添加的组件设置父组件 ID
export function useMaterialDrop(accept: string[], id: number) {
    const { addComponent } = useComponentsStore()//从useComponentsStore获取addComponent方法
    const { componentConfig } = useComponentConfigStore()//从useComponentConfigStore获取componentConfig对象
    const [messageApi, contextHolder] = message.useMessage();
    //useDrop是React DnD的核心钩子，用于定义放置目标行为，返回： canDrop: 是否允许放置（由collect函数计算）
    const [{ canDrop }, dropRef] = useDrop(() => {
        return {
            accept, // 允许接收的拖拽类型（与参数accept一致，所以就简写成一个）
            
            // 拖拽完成时触发的回调函数
            drop: (item: { type: string }, monitor) => {//item为从拖拽源传过来的对象，里面放的就是拖拽源组件的名称
                // 检查是否已在其他目标放置（避免重复处理）
                //monitor.didDrop()默认结果为false，如果在page容器内添加了一个container组件，那么monitor.didDrop()就会变为true，
                // 再想在container容器内放一个button，这时候就不会误将button也加入到page中，而是只会加在container容器内
                const didDrop = monitor.didDrop()
                if (didDrop) return//如果didDrop为true，说明已经在其他目标放置了，就直接返回
                // 显示成功消息
                messageApi.success(`${item.type}添加成功`)
                // 从组件配置仓库中获取默认属性和描述，item.type为对应的组件名称
                const props = componentConfig?.[item.type]?.defaultProps
                const desc = componentConfig?.[item.type]?.desc
                // 调用useComponentsStore仓库内的添加组件对象到json树的方法，将拖拽组件添加到json树中，然后会触发渲染函数的执行
                addComponent({
                    id: new Date().getTime(), // 使用时间戳作为唯一ID
                    name: item.type,          // 组件类型名称
                    props: props,             // 默认属性
                    desc: desc                // 组件描述
                }, id) // id为父容器ID，指定组件添加位置
            },
            // 收集拖拽状态（供组件使用）
            collect: (monitor) => ({
                // 当前是否可以放置拖拽项，会被利用到容器样式内，如果是可以放置的拖拽项，则组件边框变为设置好的颜色
                canDrop: monitor.canDrop()
            })
        }
    })
    return {
        canDrop,// 是否允许放置（用于条件渲染样式）
        dropRef,// 放置区域DOM引用（需绑定到容器元素，使其可放置组件）
        contextHolder// Ant Design消息组件的上下文（需在组件中渲染）
    }
}
